package cn.schoolwow.quickdao.module.initial.flow.table;

import cn.schoolwow.quickdao.domain.QuickDAOConfig;
import cn.schoolwow.quickdao.domain.entity.DatabaseUpgrade;
import cn.schoolwow.quickdao.domain.entity.Entity;
import cn.schoolwow.quickdao.domain.entity.SqlLog;
import cn.schoolwow.quickdao.module.database.ddl.action.service.table.CreateTableFlow;
import cn.schoolwow.quickdao.module.database.ddl.query.service.entity.HasTableFlow;
import cn.schoolwow.quickdao.module.database.dml.common.domain.GetBatchParametersSupplier;
import cn.schoolwow.quickdao.module.database.dml.common.domain.ManipulationOption;
import cn.schoolwow.quickdao.module.database.dml.instance.flow.insert.common.SetInsertInstanceParameterFlow;
import cn.schoolwow.quickdao.module.database.dml.instance.flow.insert.common.SetInsertInstanceStatementFlow;
import cn.schoolwow.quickdao.module.database.parent.flow.executor.ExecuteBatchUpdateConnectionFlow;
import cn.schoolwow.quickflow.domain.FlowContext;
import cn.schoolwow.quickflow.flow.BusinessFlow;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

public class LogRecordFlow implements BusinessFlow {
    @Override
    public void executeBusinessFlow(FlowContext flowContext) throws Exception {
        createLogTable(flowContext);
        handleSqlLog(flowContext);
    }

    @Override
    public String name() {
        return "创建SQL日志记录";
    }

    private void createLogTable(FlowContext flowContext){
        QuickDAOConfig quickDAOConfig = flowContext.checkInstanceData(QuickDAOConfig.class);
        String[] sqlLogClassNames = new String[]{DatabaseUpgrade.class.getName(), SqlLog.class.getName()};
        for(String sqlLogClassName:sqlLogClassNames){
            Entity entity = quickDAOConfig.databaseContext.entityMap.get(sqlLogClassName);
            if(null==entity){
                throw new IllegalArgumentException("日志实体类不存在!类名:"+sqlLogClassName);
            }
            boolean hasResult = (boolean) flowContext.getQuickFlow().startFlow(new HasTableFlow())
                    .putTemporaryData("tableName", entity.tableName)
                    .putTemporaryData("insertSqlLog", false)
                    .execute()
                    .checkData("hasResult");
            if(!hasResult){
                //创建表
                flowContext.getQuickFlow().startFlow(new CreateTableFlow())
                        .putData("entity", entity)
                        .putData("insertSqlLog", false)
                        .execute();
            }else{
                //比较表字段
                flowContext.getQuickFlow().startFlow(new CompareAndCreateColumnFlow())
                        .putData("entity", entity)
                        .putData("insertSqlLog", false)
                        .execute();
            }
        }
    }

    private void handleSqlLog(FlowContext flowContext){
        QuickDAOConfig quickDAOConfig = flowContext.checkInstanceData(QuickDAOConfig.class);
        Entity entity = quickDAOConfig.databaseContext.entityMap.get(SqlLog.class.getName());
        if(null==entity){
            throw new IllegalArgumentException("SqlLog日志实体类不存在!");
        }
        ManipulationOption manipulationOption = new ManipulationOption();
        manipulationOption.returnGeneratedKeys = false;

        //启动线程定时处理SQL日志
        quickDAOConfig.asyncThreadPool.execute(()->{
            while(true){
                try {
                    List<SqlLog> sqlLogList = getSqlLogInstances(quickDAOConfig);
                    if(sqlLogList.isEmpty()){
                        continue;
                    }
                    flowContext.startFlow("线程异步批处理插入SQL日志")
                            .putTemporaryData("insertSqlLog", false)
                            .putTemporaryData("entity", entity)
                            .putInstanceData(manipulationOption)
                            .putTemporaryData("name", "批处理插入SQL日志")
                            .putTemporaryData("size", sqlLogList.size())
                            .putTemporaryData("getBatchParametersSupplier",new GetBatchParametersSupplier() {
                                @Override
                                public List<Object> getBatchParameters(Integer index) throws Exception {
                                    SqlLog sqlLog = sqlLogList.get(index);
                                    flowContext.putTemporaryData("instance", sqlLog);
                                    flowContext.executeFlowList(new SetInsertInstanceParameterFlow());
                                    List<Object> parameters = (List<Object>) flowContext.getData("parameters");
                                    return parameters;
                                }
                            })
                            .next(new SetInsertInstanceStatementFlow())
                            .next(new ExecuteBatchUpdateConnectionFlow())
                            .execute();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    private List<SqlLog> getSqlLogInstances(QuickDAOConfig quickDAOConfig) throws InterruptedException {
        //退出条件为超过3秒或者个数超过1000个
        long timeout = 3000;
        long startTime = System.currentTimeMillis();

        List<SqlLog> sqlLogList = new ArrayList<>();
        SqlLog sqlLog = quickDAOConfig.logRecordOption.sqlLogBlockingQueue.poll(3, TimeUnit.SECONDS);

        while (sqlLog != null && System.currentTimeMillis() - startTime < timeout && sqlLogList.size()<1000) {
            sqlLogList.add(sqlLog);
            sqlLog = quickDAOConfig.logRecordOption.sqlLogBlockingQueue.poll(3, TimeUnit.SECONDS);
        }
        return sqlLogList;
    }
}
